﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using System.Xml;

namespace SPHelper
{
	public class Wiki
	{
		/// <summary>
		/// How to insert HTML into wiki content area
		/// </summary>
		public enum InsertionLocation
		{
			Prepend,
			Append,
			Replace,
		}

		/// <summary>
		/// Get the inner HTML for a wiki content area. Excludes the outer table and div tags
		/// </summary>
		/// <param name="wiki"></param>
		/// <param name="tableCellIndex">If content area has multiple table cells, use this to select a specific td
		/// Starts at number 1</param>
		/// <returns></returns>
		public static string GetHtml(SPListItem wiki, byte? tableCellIndex)
		{
			string o = null;
			string wikiCompleteHtml = null;
			try
			{
				// init
				if (wiki == null) { throw new Exception("wiki item passed is null"); }
				if (wiki[SPBuiltInFieldId.WikiField] != null)
				{
					wikiCompleteHtml = wiki[SPBuiltInFieldId.WikiField].ToString();
				}
				if (tableCellIndex == null || tableCellIndex == 0) { tableCellIndex = 1; }


				if (!string.IsNullOrEmpty(wikiCompleteHtml))
				{
					// convert html into xml
					// <?xml version="1.0" encoding="ISO-8859-1"?>
					System.Xml.XmlDocument wikiXml = new System.Xml.XmlDocument();
					wikiXml.LoadXml(wikiCompleteHtml);

					// get all table cells
					System.Xml.XmlNodeList tableCells = wikiXml.SelectNodes("/div/table/tbody/tr/td");
					if (tableCells == null || tableCells.Count == 0) { throw new Exception("Failed to find any table cells"); }
					if (tableCells.Count < tableCellIndex) { throw new Exception("Invalid column: " + tableCellIndex + ". Max number of tabl cells returned: " + tableCells.Count); }

					// get column innerHtml
					byte index = 1;
					foreach (System.Xml.XmlNode n in tableCells)
					{
						if (index == (byte)tableCellIndex)
						{
							o = n.SelectSingleNode("div/div").InnerXml;
						}
						index++;
					}
				}
			}
			catch (Exception ex)
			{
				SPHelper.Log.WriteError("drtuygiffdyseesataseteast", ex, "wiki complete html: " + wikiCompleteHtml);
				o = null;
			}
			return o;
		}


		/// <summary>
		/// Add html to a wiki content area, placing inside of the existing html container div/table tags
		/// </summary>
		/// <param name="wiki"></param>
		/// <param name="htmlToAdd"></param>
		/// <param name="whereToInsert"></param>
		/// <param name="tableCellIndex"></param>
		/// <returns></returns>
		public static bool AddHtml(SPListItem wiki, string htmlToAdd, InsertionLocation whereToInsert, byte? tableCellIndex, bool isSave)
		{
			bool isSuccess = false;
			string wikiCompleteHtml = null;
			try
			{
				// init
				if (wiki == null) { throw new Exception("wiki item passed is null"); }
				if (wiki[SPBuiltInFieldId.WikiField] != null)
				{
					wikiCompleteHtml = wiki[SPBuiltInFieldId.WikiField].ToString();
				}
				if (tableCellIndex == null || tableCellIndex == 0) { tableCellIndex = 1; }


				if (string.IsNullOrEmpty(wikiCompleteHtml))
				{
					// currently empty, no outer html. Simply add html
					wiki[SPBuiltInFieldId.WikiField] = htmlToAdd;
				}
				else
				{
					// convert html into xml
					// <?xml version="1.0" encoding="ISO-8859-1"?>
					System.Xml.XmlDocument wikiXml = new System.Xml.XmlDocument();
					wikiXml.LoadXml(wikiCompleteHtml);

					// get all table cells
					System.Xml.XmlNodeList tableCells = wikiXml.SelectNodes("/div/table/tbody/tr/td");
					if (tableCells == null || tableCells.Count == 0) { throw new Exception("Failed to find any table cells"); }
					if (tableCells.Count < tableCellIndex) { throw new Exception("Invalid column: " + tableCellIndex + ". Max number of tabl cells returned: " + tableCells.Count); }

					// get column innerHtml
					byte index = 1;
					bool isMatch = false;
					foreach (System.Xml.XmlNode n in tableCells)
					{
						if (index == (byte)tableCellIndex)
						{
							isMatch = true;
							if (whereToInsert == InsertionLocation.Prepend)
							{
								n.SelectSingleNode("div/div").InnerXml = htmlToAdd + n.SelectSingleNode("div/div").InnerXml;
							}
							else if (whereToInsert == InsertionLocation.Replace)
							{
								n.SelectSingleNode("div/div").InnerXml = htmlToAdd;
							}
							else if (whereToInsert == InsertionLocation.Append)
							{
								n.SelectSingleNode("div/div").InnerXml += htmlToAdd;
							}
						}
						index++;
					}

					if (!isMatch) { throw new Exception("Failed to find table cell for column: " + tableCellIndex); }

					// pass xml back to wiki item
					wiki[SPBuiltInFieldId.WikiField] = wikiXml.OuterXml;
				}

				// save
				if (isSave) { wiki.Update(); }

				// assume success 
				isSuccess = true;
			}
			catch (Exception ex)
			{
				SPHelper.Log.WriteError("zdstguftudrsdrstrd6dfdx", ex, "wiki complete html: " + wikiCompleteHtml);
				isSuccess = false;
			}
			return isSuccess;
		}


		
		/// <summary>
		/// replace element contents, such as a div with unique id, replaces all the innterHtml
		/// </summary>
		/// <param name="wiki"></param>
		/// <param name="elementName">tag name, such as div or p</param>
		/// <param name="elementIdToReplace">unique id for that tag</param>
		/// <param name="elementInstanceToReplace">if null or 0, will replace all, if 2, then replaces 2nd instance of element with passed id</param>
		/// <param name="htmlToReplaceWith">new innerHtml</param>
		/// <returns></returns>
		public static bool ReplaceElementContent(SPListItem wiki, string elementName, string elementIdToReplace, string htmlToReplaceWith, bool isSave)
		{
			bool isSuccess = false;
			string wikiCompleteHtml = null;
			try
			{
				// init
				if (wiki == null) { throw new Exception("wiki item passed is null"); }
				if (wiki[SPBuiltInFieldId.WikiField] != null)
				{
					wikiCompleteHtml = wiki[SPBuiltInFieldId.WikiField].ToString();
				}
				if (string.IsNullOrEmpty(elementName)) { throw new Exception("elementName passed is null"); }


				// call utility to replace
				int numberElementsAffected = 0;
				wiki[SPBuiltInFieldId.WikiField] = Xml.ReplaceElements(wiki[SPBuiltInFieldId.WikiField].ToString(), 
					htmlToReplaceWith, elementName, elementIdToReplace, false, ref numberElementsAffected);
				
				// save?
				if (isSave) { wiki.Update(); }

				// assume success 
				isSuccess = true;
			}
			catch (Exception ex)
			{
				SPHelper.Log.WriteError("sryestddGGaer44", ex, "wiki complete html: " + wikiCompleteHtml);
				isSuccess = false;
			}
			return isSuccess;
		}


		/// <summary>
		/// Delete element(s) using name and id passed
		/// </summary>
		/// <param name="wiki"></param>
		/// <param name="elementName">element name, such div, p, or table</param>
		/// <param name="elementId">id="" attribute</param>
		/// <param name="elementInstance"></param>
		/// <returns></returns>
		public static bool DeleteElements(SPListItem wiki, string elementName, string elementId, byte? elementInstance, bool isSave)
		{
			bool isSuccess = false;
			string wikiCompleteHtml = null;
			try
			{
				// init
				if (wiki == null) { throw new Exception("wiki item passed is null"); }
				if (wiki[SPBuiltInFieldId.WikiField] != null)
				{
					wikiCompleteHtml = wiki[SPBuiltInFieldId.WikiField].ToString();
				}
				if (string.IsNullOrEmpty(elementId)) { throw new Exception("elementId passed is null"); }
				if (string.IsNullOrEmpty(elementName)) { throw new Exception("elementName passed is null"); }
				if (elementInstance == null) { elementInstance = 0; }


				// convert html into xml
				// <?xml version="1.0" encoding="ISO-8859-1"?>
				System.Xml.XmlDocument wikiXml = new System.Xml.XmlDocument();
				wikiXml.LoadXml(wikiCompleteHtml);

				// get all divs with id passed
				System.Xml.XmlNodeList elements = wikiXml.SelectNodes("//" + elementName + "[@id='" + elementId + "']");
				if (elements != null && elements.Count > 0)
				{
					for (byte i = 0; i < elements.Count; i++)
					{
						if (elementInstance == 0 || ((elementInstance - 1) == i))
						{
							elements[i].ParentNode.RemoveChild(elements[i]);
						}
					}

					// pass xml back to wiki item
					wiki[SPBuiltInFieldId.WikiField] = wikiXml.OuterXml;
				}

				// save
				if (isSave) { wiki.Update(); }

				// assume success 
				isSuccess = true;
			}
			catch (Exception ex)
			{
				SPHelper.Log.WriteError("5e6ujdsrer4e54r", ex, "wiki complete html: " + wikiCompleteHtml);
				isSuccess = false;
			}
			return isSuccess;
		}


		/// <summary>
		/// Removes all inner html, keeps existing text layout
		/// </summary>
		/// <param name="wiki"></param>
		/// <returns></returns>
		public static bool DeleteHtml(SPListItem wiki, bool isSave)
		{
			bool isSuccess = false;
			string wikiCompleteHtml = null;
			try
			{
				// init
				if (wiki == null) { throw new Exception("wiki item passed is null"); }
				if (wiki[SPBuiltInFieldId.WikiField] != null)
				{
					wikiCompleteHtml = wiki[SPBuiltInFieldId.WikiField].ToString();
				}


				if (!string.IsNullOrEmpty(wikiCompleteHtml))
				{
					// convert html into xml
					// <?xml version="1.0" encoding="ISO-8859-1"?>
					System.Xml.XmlDocument wikiXml = new System.Xml.XmlDocument();
					wikiXml.LoadXml(wikiCompleteHtml);

					// get all table cells
					System.Xml.XmlNodeList tableCells = wikiXml.SelectNodes("/div/table/tbody/tr/td");
					if (tableCells == null || tableCells.Count == 0) { throw new Exception("Failed to find any table cells"); }

					foreach (System.Xml.XmlNode n in tableCells)
					{
						n.SelectSingleNode("div/div").InnerXml = string.Empty;
					}

					// pass xml back to wiki item
					wiki[SPBuiltInFieldId.WikiField] = wikiXml.OuterXml;
				}

				// save
				if (isSave) { wiki.Update(); }

				// assume success 
				isSuccess = true;
			}
			catch (Exception ex)
			{
				SPHelper.Log.WriteError("r54ythrsdrsdsr5r", ex, "wiki complete html: " + wikiCompleteHtml);
				isSuccess = false;
			}
			return isSuccess;
		}

	}
}
